package com.xiaohan.usercenter.service.impl;
import java.util.Date;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaohan.usercenter.exception.CustomException;
import com.xiaohan.usercenter.model.domain.User;
import com.xiaohan.usercenter.service.UserService;
import com.xiaohan.usercenter.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.xiaohan.usercenter.common.ErrorCode.*;
import static com.xiaohan.usercenter.constant.UserConstant.USER_LOGIN_STATE;

/**
 * @author xiaohan
 * @description 针对表【user(用户信息表)】的数据库操作Service实现
 * @createDate 2025-02-23 14:59:04
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

	@Autowired
	private UserMapper userMapper;

	/**
	 * 密码加密时的盐值
	 */
	private static final String salt = "xiaohan";

	@Override
	public Long register(String userAccount, String password, String checkPassword) {
		//判空
		//存在任一内容为空则返回true
		// TODO 修改为自定义异常
		if (StringUtils.isAnyBlank(userAccount, password, checkPassword)) return (long) -1;
		//账号不小于4位
		if (userAccount.length() < 4) {
			throw new CustomException(PARAMS_ERROR,"账号过短");
		}
		//密码不小于8位
		if (password.length() < 8 || checkPassword.length() < 8) {
			throw new CustomException(PARAMS_ERROR,"密码过短");
		}
		//账号不包含特殊字符
		if(isAccountEnvalid(userAccount)){   //存在上述的任一违法字符
			throw new CustomException(PARAMS_ERROR,"账号含特殊字符");
		}
		//两次密码输入相同
		if (!password.equals(checkPassword)) {
			throw new CustomException(PARAMS_ERROR,"两次密码输入不一致");
		}

		//账号不重复：account字段所在的列不存在注册的账号
		Long count = userMapper.selectCount(new QueryWrapper<User>().eq("account", userAccount));
		if (count > 0) {  //存在
			throw new CustomException(PARAMS_ERROR,"用户已存在");
		}

		//密码加密
		String encryptPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes(StandardCharsets.UTF_8));
		//数据库中新增
		User newUser = new User();
		newUser.setAccount(userAccount);
		newUser.setPassword(encryptPassword);
		int result = userMapper.insert(newUser);
		if (result < 0) {
			throw new CustomException(SYSTEM_ERROR,"系统异常");
		}

		return newUser.getId();
	}

	@Override
	public User login(String userAccount, String passwordm, HttpServletRequest request) {
		//判空
		if (StringUtils.isAnyBlank(userAccount, passwordm)) {   //存在任一内容为空则返回true
			// TODO 修改为自定义异常
			throw new CustomException(PARAMS_ERROR,"输入内容含空");
		}
		//账号不小于4位
		if (userAccount.length() < 4) {
			throw new CustomException(PARAMS_ERROR,"账号过短");
		}
		//密码不小于8位
		if (passwordm.length() < 8) {
			throw new CustomException(PARAMS_ERROR,"密码过短");
		}
		//账号不包含特殊字符
		if(isAccountEnvalid(userAccount)){
			log.info("user login failed,account is envalid!");
			throw new CustomException(PARAMS_ERROR,"账号含特殊字符");
		}

		//查找是否存在该用户（密码需加密）
		String encryptPassword = DigestUtils.md5DigestAsHex((salt + passwordm).getBytes(StandardCharsets.UTF_8));   //加密后的密码
		QueryWrapper<User> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("account", userAccount);
		queryWrapper.eq("password", encryptPassword);
		User rsUser = userMapper.selectOne(queryWrapper);

		//当用户的该字段值为1时，即状态为被逻辑删除了（如注销），也表现为查询不到该用户
		//可以通过配置Mybatis-plus的支持逻辑删除功能实现（yml中配置0还是1代表逻辑删除，随后在目标字段上添加@TableLogic）
//		if(rsUser.getIsDelete() == 1){
//			return null;
//		}

		if(rsUser == null){   //没找到
			log.info("user login failed,account or password is error!");
			throw new CustomException(PARAMS_ERROR,"账号或密码错误");
		}

		//返回给前端和保存在会话中的用户信息需要进行数据脱敏（不将密码返回）：作用类似于DTO,此处不单独封装成一个userDTO类
		User dtoUser = getSafetyUser(rsUser);

		//在session中记录用户的登陆状态
		request.getSession().setAttribute(USER_LOGIN_STATE, dtoUser);  //脱敏后的用户
		//测试：输出sessionid
		log.info("user login success!----sessionID:{}", request.getSession().getId());

		//返回给前端
		return dtoUser;
	}

	/**
	 * 用户注销
	 * @param request 维护会话
	 * @return
	 */
	@Override
	public int logout(HttpServletRequest request) {
		//从session中移除代表当前用户的登录态
		request.getSession().removeAttribute(USER_LOGIN_STATE);
		if(request.getSession().getAttribute(USER_LOGIN_STATE) == null){
			log.info("user logout success!");
		}
		return 1;
	}

	/**
	 * 账号是否无效
	 * @param userAccount 账号
	 * @return true 格式非法 false 账号可用
	 */
	private boolean isAccountEnvalid(String userAccount) {
		String regEx = "[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]|\n|\r|\t";
		Pattern p = Pattern.compile(regEx);
		Matcher m = p.matcher(userAccount);
		return m.find();  //m.find()为true代表存在非法格式
	}

	/**
	 * 对用户密码信息脱敏（没有单独封装一个DTO类，此处采用手动脱敏）
	 * @param originUser 获取到的实际用户
	 * @return 密码脱敏后的新用户UserDTO
	 */
	@Override
	public User getSafetyUser(User originUser){
		//最好也判空 防止空指针异常
		if(originUser == null){
			throw new CustomException(NULL_ERROR,"用户不存在");
		}
		User dtoUser = new User();
		dtoUser.setId(originUser.getId());
		dtoUser.setUserName(originUser.getUserName());
		dtoUser.setAccount(originUser.getAccount());
//		dtoUser.setPassword(rsUser.getPassword());  不设置返回
		dtoUser.setGender(originUser.getGender());
		dtoUser.setAvatarUrl(originUser.getAvatarUrl());
		dtoUser.setPhone(originUser.getPhone());
		dtoUser.setEmail(originUser.getEmail());
		dtoUser.setRole(originUser.getRole());
		dtoUser.setCreateTime(new Date());
		dtoUser.setUpdateTime(new Date());
		return dtoUser;
	}

}




